<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>GC与垃圾回收分代 | Eetal&#39;s Blog</title>

  <!-- keywords -->
  

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="欢迎查看Eetal的第十三篇博客–GC与垃圾回收分代 gc与finalize网上很多博客简略的说确保对象死活需要经过两次标记这是错误的。Object有个finalize，默认是空实现被回收时会判断这个对象是否重写了finalize方法，如果没有就直接回收否则会把该对象加入一个f队列（代表需要执行回收方法的队列）jvm会分配一个执行finalize的线程去执行这个队列每个对象的finalize方法，">
<meta property="og:type" content="article">
<meta property="og:title" content="GC与垃圾回收分代">
<meta property="og:url" content="http://eetal.gitee.io/blog/2019/03/30/GC与垃圾回收分代/index.html">
<meta property="og:site_name" content="Eetal&#39;s Blog">
<meta property="og:description" content="欢迎查看Eetal的第十三篇博客–GC与垃圾回收分代 gc与finalize网上很多博客简略的说确保对象死活需要经过两次标记这是错误的。Object有个finalize，默认是空实现被回收时会判断这个对象是否重写了finalize方法，如果没有就直接回收否则会把该对象加入一个f队列（代表需要执行回收方法的队列）jvm会分配一个执行finalize的线程去执行这个队列每个对象的finalize方法，">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2019-03-30T08:22:01.114Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="GC与垃圾回收分代">
<meta name="twitter:description" content="欢迎查看Eetal的第十三篇博客–GC与垃圾回收分代 gc与finalize网上很多博客简略的说确保对象死活需要经过两次标记这是错误的。Object有个finalize，默认是空实现被回收时会判断这个对象是否重写了finalize方法，如果没有就直接回收否则会把该对象加入一个f队列（代表需要执行回收方法的队列）jvm会分配一个执行finalize的线程去执行这个队列每个对象的finalize方法，">
  
    <link rel="alternative" href="/atom.xml" title="Eetal&#39;s Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="http://www.yangyitao.top/FiveChess/resource/ico/favicon.ico">
  
  <link rel="stylesheet" href="/blog/css/style.css">
  
  

  <script src="//cdn.bootcss.com/require.js/2.3.2/require.min.js"></script>
  <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>

  
</head>
<body>
  <div id="container">
    <div id="particles-js"></div>
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
	<header id="header" class="inner">
		<a href="/" class="profilepic">
			
			<img lazy-src="/blog/images/head.jpg" class="js-avatar">
			
		</a>

		<hgroup>
		  <h1 class="header-author"><a href="/">Eetal</a></h1>
		</hgroup>

		
		<p class="header-subtitle">java coder</p>
		

		
			<div class="switch-btn">
				<div class="icon">
					<div class="icon-ctn">
						<div class="icon-wrap icon-house" data-idx="0">
							<div class="birdhouse"></div>
							<div class="birdhouse_holes"></div>
						</div>
						<div class="icon-wrap icon-ribbon hide" data-idx="1">
							<div class="ribbon"></div>
						</div>
						
						<div class="icon-wrap icon-link hide" data-idx="2">
							<div class="loopback_l"></div>
							<div class="loopback_r"></div>
						</div>
						
						
					</div>
					
				</div>
				<div class="tips-box hide">
					<div class="tips-arrow"></div>
					<ul class="tips-inner">
						<li>菜单</li>
						<li>标签</li>
						
						<li>友情链接</li>
						
						
					</ul>
				</div>
			</div>
		

		<div class="switch-area">
			<div class="switch-wrap">
				<section class="switch-part switch-part1">
					<nav class="header-menu">
						<ul>
						
							<li><a href="/blog/">Home</a></li>
				        
							<li><a href="/blog/archives">Archives</a></li>
				        
						</ul>
					</nav>
					<nav class="header-nav">
						<div class="social">
							
						</div>
					</nav>
				</section>
				
				
				<section class="switch-part switch-part2">
					<div class="widget tagcloud" id="js-tagcloud">
						
					</div>
				</section>
				
				
				
				<section class="switch-part switch-part3">
					<div id="js-friends">
					
			          <a target="_blank" class="main-nav-link switch-friends-link" href="https://github.com/smackgg/hexo-theme-smackdown">smackdown</a>
			        
			        </div>
				</section>
				

				
			</div>
		</div>
	</header>				
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
  	<div class="overlay">
  		<div class="slider-trigger"></div>
  		<h1 class="header-author js-mobile-header hide">Eetal</h1>
  	</div>
	<div class="intrude-less">
		<header id="header" class="inner">
			<div class="profilepic">
				<img lazy-src="/blog/images/head.jpg" class="js-avatar">
			</div>
			<hgroup>
			  <h1 class="header-author">Eetal</h1>
			</hgroup>
			
			<p class="header-subtitle">java coder</p>
			
			<nav class="header-menu">
				<ul>
				
					<li><a href="/blog/">Home</a></li>
		        
					<li><a href="/blog/archives">Archives</a></li>
		        
		        <div class="clearfix"></div>
				</ul>
			</nav>
			<nav class="header-nav">
				<div class="social">
					
				</div>
			</nav>
		</header>				
	</div>
</nav>
      <div class="body-wrap"><article id="post-GC与垃圾回收分代" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2019/03/30/GC与垃圾回收分代/" class="article-date">
  	<time datetime="2019-03-30T02:53:36.250Z" itemprop="datePublished">2019-03-30</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      GC与垃圾回收分代
      
    </h1>
  

      </header>
      
      <div class="article-info article-info-post">
        
        

        
        <div class="clearfix"></div>
      </div>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>欢迎查看Eetal的第十三篇博客–GC与垃圾回收分代</p>
<h2 id="gc与finalize"><a href="#gc与finalize" class="headerlink" title="gc与finalize"></a>gc与finalize</h2><p>网上很多博客简略的说确保对象死活需要经过两次标记这是错误的。<br>Object有个finalize，默认是空实现<br>被回收时会判断这个对象是否重写了finalize方法，如果没有就直接回收<br>否则会把该对象加入一个f队列（代表需要执行回收方法的队列）<br>jvm会分配一个执行finalize的线程去执行这个队列每个对象的finalize方法，如果在finalize方法中对象吧自己的this给不在finalize队列中的对象引用，则将其从finalize队列移除<br>jvm并不保证执行finalize的线程绝对会执行结束，而是超过一个固定时间以后就终止（防止死锁）。<br>finalize线程终止后，其中还保留的对象都会被回收</p>
<h2 id="判断对象是否存活"><a href="#判断对象是否存活" class="headerlink" title="判断对象是否存活"></a>判断对象是否存活</h2><p>以前采用过标记法，即每个对象加一个计数器，被引用了+1，取消引用-1.当为0代表可以回收<br>此种方法会导致无法处理循环引用(A引用B，B引用A且而GCroot没有任何对象引用A和B，则A和B永远不会被回收)，因此被遗弃了<br>现在普遍使用GCroot扫描方法</p>
<h2 id="GCRoot"><a href="#GCRoot" class="headerlink" title="GCRoot"></a>GCRoot</h2><p>以下对象可以作为GCroot<br>Class - 由系统类加载器(system class loader)加载的对象，这些类是不能够被回收的，他们可以以静态字段的方式保存持有其它对象。<br>        //其他类加载器加载的对象，jvm默认不回收，除非进行特殊指定<br>Thread - 活着的线程<br>Stack Local - Java方法栈的local变量或参数<br>JNI Local - JNI方法的local变量或参数<br>JNI Global - 全局JNI引用<br>Monitor Used - 用于同步的监控对象（锁）<br>Held by JVM - 用于JVM特殊目的由GC保留的对象，但实际上这个与JVM的实现是有关的。可能已知的一些类型是：系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。</p>
<p>扫描过程:<br>    从GCroot开始扫描，如果可达的对象则为存活<br>    即为一个连通图的判断，不在图里的其他元素默认为死亡</p>
<h2 id="分代回收"><a href="#分代回收" class="headerlink" title="分代回收"></a>分代回收</h2><p>jdk1.7以前<br>java把堆内存分为两块，新生代和老生代<br>还有一块保存静态变量，常量和Class对象的永生代保存在方法区</p>
<p>新生代采用复制算法<br>老生代使用标记整理算法<br>永生代一般不回收，只有当需要加载Class而内存不够才会触发fullgc进行回收，会和老年代一起回收（标记整理）</p>
<p>新生代又分为 一块eden 和 两块survivor</p>
<p>参数:    指定新生代大小    -XX:NewSize<br>        指定老年代与新生代大小比例        -XX:NewRatio<br>        指定新生代中伊甸园和存活地大小比例: -XX:SurvivorRatio</p>
<p>刚开始new出来的对象都在伊甸园(eden)<br>然后一块survivor标记为存活地</p>
<h2 id="复制算法"><a href="#复制算法" class="headerlink" title="复制算法"></a>复制算法</h2><p>触发minor gc以后，会把另一块没有标记的空的survivor标记为存活地<br>会把eden中存活的对象和旧存活地的还活着的对象放进这块新的存活地,然后把旧存活地和伊甸园清空<br>当然如果存活地大小不足以容纳时，多余的对象会直接进入老年代<br>对象第一次进入survivor时，标记年龄为1<br>每次在survivor之间转移时年龄会增长，达到某个值时，就不进入新的存活地而是直接进入老年代<br>这个年龄可以通过jvm参数设置：-XX:MaxTenuringThreshold</p>
<h2 id="标记整理算法"><a href="#标记整理算法" class="headerlink" title="标记整理算法"></a>标记整理算法</h2><p>首先会遍历所有对象，标记还存活的对象，并清理掉死亡的对象，然后将存活的对象整理（挨到一起）<br>整理的目的和磁盘碎片压缩的道理一样，整理后才能留出更大的空间留给大对象，避免出现大量碎片<br>因为标记整理算法相对复制算法更慢，但是不需要额外的备用空间，<br>而minor gc触发频繁，老年代的gc触发较少，但是可能会累计较大空间<br>因此minor gc使用复制算法,major gc使用标记整理算法</p>
<p>对新生代触发的gc称为minor gc，而对老生代触发的gc称为major gc<br>fullgc是指触发所有的回收（包括对永久代的回收）</p>
<h2 id="垃圾回收器"><a href="#垃圾回收器" class="headerlink" title="垃圾回收器"></a>垃圾回收器</h2><h3 id="新生代"><a href="#新生代" class="headerlink" title="新生代"></a>新生代</h3><h4 id="Serial串行回收器"><a href="#Serial串行回收器" class="headerlink" title="Serial串行回收器"></a>Serial串行回收器</h4><p>基于单线程的回收器，在运行时会导致Stop The World，但是效率高，使用的算法就是复制算法<br>可以和CMS搭配使用</p>
<h4 id="ParNew回收器"><a href="#ParNew回收器" class="headerlink" title="ParNew回收器"></a>ParNew回收器</h4><p>Parallel New Generation<br>Serial回收器的多线程版本，因为是多线程版本，所以不用触发Stop the world<br>但是效率不太好，因为需要花开销在线程的切换调度销毁上<br>当然在多cpu电脑上会更有优势<br>可以和CMS搭配使用</p>
<h4 id="Parallel-Scavenge回收器"><a href="#Parallel-Scavenge回收器" class="headerlink" title="Parallel Scavenge回收器"></a>Parallel Scavenge回收器</h4><p>与ParNew类似，都是复制算法的并行收集器<br>但是Parallel Scavenge的目标是达到一个可控的吞吐量<br>吞吐量=程序运行时间/（程序运行时间+GC时间）<br>Parallel Scavenge提供了两个参数用以精确控制吞吐量<br>分别是用以控制最大GC停顿时间的-XX:MaxGCPauseMillis及直接控制吞吐量的参数-XX:GCTimeRatio.<br>同时可以设置垃圾自适应调配策略，由虚拟机自动调优<br>由于是Parallel Scavenge没有使用原本HotSpot其它GC通用的那个GC框架，所以不能跟使用了那个框架的CMS搭配使用。</p>
<h3 id="老年代"><a href="#老年代" class="headerlink" title="老年代"></a>老年代</h3><h4 id="SerialOld回收器"><a href="#SerialOld回收器" class="headerlink" title="SerialOld回收器"></a>SerialOld回收器</h4><p>Serial的老年代版本，还是单线程也会触发Stop the world，不过使用的是标记整理算法</p>
<h4 id="ParallelOld回收器"><a href="#ParallelOld回收器" class="headerlink" title="ParallelOld回收器"></a>ParallelOld回收器</h4><p>Parallel Scavenge的年老代版,使用标记整理算法，并行</p>
<h4 id="CMS回收器"><a href="#CMS回收器" class="headerlink" title="CMS回收器"></a>CMS回收器</h4><p>Concurrent Mark Sweep，并发回收器，旨在减少STW时间（通过两次标记，第二次只查看dirty的）<br>在G1出现前的主流一般server版本jvm就是ParNew+CMS<br>过程<br>初始标记：该阶段只标记GC Root节点直接引用的老年代节点，会造成STW，但是时间很短。（因为只标记被直接引用的）<br>并发标记：GC ROOT TRACING。遍历老年代，然后标记所有存活的对象（包括不是gcRoot直接引用的），它会根据上个阶段找到的 GC Roots 遍历查找<br>          在并发标记阶段被修改的节点（新降临到老年代的对象以及在并发阶段被修改了的对象）的对象会被标记为dirty，加入Dirty队列<br>重新标记：stop the world<br>          遍历DirtyCard，更新标记被修改的老年代对象<br>          停顿时间比初始标记稍长，但远比并发标记短<br>并发清理：遍历老年代清理死亡对象，整理空间</p>
<h3 id="请移步"><a href="#请移步" class="headerlink" title="请移步"></a>请移步</h3><p>个人主页: <a href="http://yangyitao.top" target="_blank" rel="noopener">yangyitao.top</a></p>

      
    </div>
    
  </div>
  
    
<nav id="article-nav">
  
    <a href="/blog/2019/03/30/java的四种引用类型/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">&lt;</strong>
      <div class="article-nav-title">
        
          java的四种引用类型
        
      </div>
    </a>
  
  
    <a href="/blog/2019/03/26/并发基石-AQS与Condition/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-title">并发基石-AQS与Condition</div>
      <strong class="article-nav-caption">&gt;</strong>
    </a>
  
</nav>

  
</article>


<div class="ds-share share" data-thread-key="GC与垃圾回收分代" data-title="GC与垃圾回收分代" data-url="http://eetal.gitee.io/blog/blog/2019/03/30/GC与垃圾回收分代/"  data-images="/blog/images/head.jpg" data-content="GC与垃圾回收分代">
    <div class="ds-share-inline">
      <ul  class="ds-share-icons-16">
      	<li data-toggle="ds-share-icons-more"><a class="ds-more" href="javascript:void(0);">分享到：</a></li>
        <li><a class="ds-weibo" href="javascript:void(0);" data-service="weibo">微博</a></li>
        <li><a class="ds-qzone" href="javascript:void(0);" data-service="qzone">QQ空间</a></li>
        <li><a class="ds-qqt" href="javascript:void(0);" data-service="qqt">腾讯微博</a></li>
        <li><a class="ds-wechat" href="javascript:void(0);" data-service="wechat">微信</a></li>
      </ul>
      <div class="ds-share-icons-more">
      </div>
    </div>
 </div>
 





</div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info">
      <div class="footer-left">
        &copy; 2019 Eetal
      </div>
        <div class="footer-right">
          <a href="http://hexo.io/" target="_blank">Hexo</a>  Theme <a href="https://github.com/smackgg/hexo-theme-smackdown" target="_blank">Smackdown</a>
        </div>
    </div>
  </div>
</footer>
    </div>
    
  <link rel="stylesheet" href="/blog/fancybox/jquery.fancybox.css">


<script>
	var yiliaConfig = {
		fancybox: true,
		mathjax: true,
		animate: true,
		isHome: false,
		isPost: true,
		isArchive: false,
		isTag: false,
		isCategory: false,
		open_in_new: false
	}
</script>
<script src="/blog/js/main.js"></script>



<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    tex2jax: {
        inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
        processEscapes: true,
        skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    }
});

MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
        all[i].SourceElement().parentNode.className += ' has-jax';                 
    }       
});
</script>

<script src="//cdn.bootcss.com/mathjax/2.7.0/MathJax.js"></script>


  </div>
</body>
</html>